#include "GLWidget.h"
//--------------------------------
// special and default constructor
//--------------------------------
GLWidget::GLWidget(QWidget *parent): QGLWidget(parent)
{
    coordy = 1.0f;
    // specifies the display format of the OpenGL rendering context
    _format.setRgba(true);
    _format.setDepth(true);
    _format.setDoubleBuffer(true);

    setFormat(_format);
}

//--------------------------------------------------------------------------------------
// this virtual function is called once before the first call to paintGL() or resizeGL()
//--------------------------------------------------------------------------------------
void GLWidget::initializeGL()
{
    // creating a perspective projection matrix
    glMatrixMode(GL_PROJECTION);

    glLoadIdentity();

    _aspect = (float)width() / (float)height();
    _z_near = 1.0;
    _z_far = 1000.0;
    _fovy = 45.0;

    gluPerspective(_fovy, _aspect, _z_near, _z_far);

    // setting the model view matrix
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    _eye[0] = _eye[1] = 0.0, _eye[2] = 10.0;
    _center[0] = _center[1] = _center[2] = 0.0;
    _up[0] = _up[2] = 0.0, _up[1] = 1.0;

    gluLookAt(_eye[0], _eye[1], _eye[2], _center[0], _center[1], _center[2], _up[0], _up[1], _up[2]);

    // enabling depth test
    glEnable(GL_DEPTH_TEST);

    // setting the color of background
    glClearColor(0.0, 0.0, 0.0, 1.0);

    // initial values of transformation parameters
    _zoom = 0.1;
    _angle_x = _angle_y = _angle_z = 0.0;
    _trans_x = _trans_y = _trans_z = 0.0;
}

//-----------------------
// the rendering function
//-----------------------
void GLWidget::paintGL()
{
    // clears the color and depth buffers
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // stores/duplicates the original model view matrix
    glPushMatrix();

        // applying transformations
        glRotatef(_angle_x, 1.0, 0.0, 0.0);
        glRotatef(_angle_y, 0.0, 1.0, 0.0);
        glRotatef(_angle_z, 0.0, 0.0, 1.0);

        glTranslated(_trans_x, _trans_y, _trans_z);

        glScaled(_zoom, _zoom, _zoom);

        // render something

    glBegin(GL_QUADS);

    // TOP
                    glColor3f(1.0f, 1.0f, 0.0f); // YELLOW
            glVertex3f( 1.0f, coordy,-1.0f);
                    glColor3f(0.0f, 1.0f, 0.0f); // GREEN
            glVertex3f(-1.0f, coordy,-1.0f);
                    glColor3f(0.0f, 1.0f, 1.0f); // CYAN
            glVertex3f(-1.0f, coordy, 1.0f);
                    glColor3f(1.0f, 1.0f, 1.0f); // WHITE
            glVertex3f( 1.0f, coordy, 1.0f);

    // BOTTOM
                    glColor3f(1.0f, 0.0f, 1.0f); // MAGMENTA
            glVertex3f( 1.0f,-coordy, 1.0f);
                    glColor3f(0.0f, 0.0f, 1.0f); // BLUE
            glVertex3f(-1.0f,-coordy, 1.0f);
                    glColor3f(0.0f, 0.0f, 0.0f); // BLACK
            glVertex3f(-1.0f,-coordy,-1.0f);
                    glColor3f(1.0f, 0.0f, 0.0f); // RED
            glVertex3f( 1.0f,-coordy,-1.0f);

    // FRONT
                    glColor3f(1.0f, 1.0f, 1.0f); // WHITE
            glVertex3f( 1.0f, coordy, 1.0f);
                    glColor3f(0.0f, 1.0f, 1.0f); // CYAN
            glVertex3f(-1.0f, coordy, 1.0f);
                    glColor3f(0.0f, 0.0f, 1.0f); // BLUE
            glVertex3f(-1.0f,-coordy, 1.0f);
                    glColor3f(1.0f, 0.0f, 1.0f); // MAGMENTA
            glVertex3f( 1.0f,-coordy, 1.0f);

    // BACK
                    glColor3f(1.0f, 0.0f, 0.0f); // RED
            glVertex3f( 1.0f,-coordy,-1.0f);
                    glColor3f(0.0f, 0.0f, 0.0f); // BLACK
            glVertex3f(-1.0f,-coordy,-1.0f);
                    glColor3f(0.0f, 1.0f, 0.0f); // GREEN
            glVertex3f(-1.0f, coordy,-1.0f);
                    glColor3f(1.0f, 1.0f, 0.0f); // YELLOW
            glVertex3f( 1.0f, coordy,-1.0f);

    // LEFT
                    glColor3f(0.0f, 1.0f, 1.0f); // CYAN
            glVertex3f(-1.0f, coordy, 1.0f);
                    glColor3f(0.0f, 1.0f, 0.0f); // GREEN
            glVertex3f(-1.0f, coordy,-1.0f);
                    glColor3f(0.0f, 0.0f, 0.0f); // BLACK
            glVertex3f(-1.0f,-coordy,-1.0f);
                    glColor3f(0.0f, 0.0f, 1.0f); // BLUE
            glVertex3f(-1.0f,-coordy, 1.0f);
    // RIGHT
                    glColor3f(1.0f, 1.0f, 0.0f); // YELLOW
            glVertex3f( 1.0f, coordy,-1.0f);
                    glColor3f(1.0f, 1.0f, 1.0f); // WHITE
            glVertex3f( 1.0f, coordy, 1.0f);
                    glColor3f(1.0f, 0.0f, 1.0f); // MAGMENTA
            glVertex3f( 1.0f,-coordy, 1.0f);
                    glColor3f(1.0f, 0.0f, 0.0f); // RED
            glVertex3f( 1.0f,-coordy,-1.0f);
    glEnd();

    // pops the current matrix stack, replacing the current matrix with the one below it on the stack,
    // i.e., the original model view matrix is restored
    glPopMatrix();
}

//----------------------------------------------------------------------------
// when the main window is resized one needs to redefine the projection matrix
//----------------------------------------------------------------------------
void GLWidget::resizeGL(int w, int h)
{
    // setting the new size of the rendering context
    glViewport(0, 0, w, h);

    // redefining the projection matrix
    glMatrixMode(GL_PROJECTION);

    glLoadIdentity();

    _aspect = (float)w / (float)h;

    gluPerspective(_fovy, _aspect, _z_near, _z_far);

    // switching back to the model view matrix
    glMatrixMode(GL_MODELVIEW);

    updateGL();
}

//-----------------------------------
// implementation of the public slots
//-----------------------------------

void GLWidget::mod_angle_x(int value)
{
    _angle_x -= value;
    if (_angle_x < -180) _angle_x = 360 + _angle_x;
    if (_angle_x >  180) _angle_x = _angle_x - 360;
    updateGL();
}

void GLWidget::set_angle_x(int value)
{
    if (_angle_x != value)
    {
        _angle_x = value;
        updateGL();
    }
}

void GLWidget::set_angle_y(int value)
{
    if (_angle_y != value)
    {
        _angle_y = value;
        updateGL();
    }
}

void GLWidget::set_angle_z(int value)
{
    if (_angle_z != value)
    {
        _angle_z = value;
        updateGL();
    }
}

void GLWidget::set_zoom_factor(double value)
{
    if (_zoom != value)
    {
        _zoom = value;
        updateGL();
    }
}

void GLWidget::set_trans_x(double value)
{
    if (_trans_x != value)
    {
        _trans_x = value;
        updateGL();
    }
}

void GLWidget::set_trans_y(double value)
{
    if (_trans_y != value)
    {
        _trans_y = value;
        updateGL();
    }
}

void GLWidget::set_trans_z(double value)
{
    if (_trans_z != value)
    {
        _trans_z = value;
        updateGL();
    }
}
